package com.zhentao.device.Controller;

import com.zhentao.device.dome.WaterQualityMonitor;
import com.zhentao.device.service.impl.WaterQualityAnomalyServiceImpl;
import com.zhentao.login.service.impl.WaterQualityDataServiceImpl;
import com.zhentao.pojo.WaterQualityAnomaly;
import com.zhentao.pojo.WaterQualityData;
import com.zhentao.util.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zhentao.util.ResultVo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author "杨旭朋"
 * @ClassName: WaDeviceController
 * @date 2025年09月22日 18:59
 */
@RestController
@RequestMapping("Device")
public class WaDeviceController {

    @Autowired
    private WaterQualityMonitor waterQualityMonitor;
    @Autowired
    WaterQualityDataServiceImpl waterQualityDataService;
    @Autowired
    WaterQualityAnomalyServiceImpl waterQualityAnomalyService;
    @Autowired
    RedisClient redisClient;

    // 仅用于控制持久化频率（按分钟）
    private volatile long lastPersistMinute = -1L;

    /**
     * @title: DeviceStatus
     * @desc: 记录水质方法
     * @params ()
     * @return: Result
     * @author: 杨旭朋
     * @date: 2025/9/23 10:08
     */
    @Scheduled(fixedRate = 1000)
    public void DeviceStatus() {
        long startTime = System.currentTimeMillis();
        System.out.println("🕐 定时器执行: " + startTime);
        WaterQualityData waterQualityData = WaterQualityMonitor.DeviceStatus();

        // 进行报警检查（实时）
        warning(waterQualityData);

        // 仅每分钟存储一次（数据库 + Redis）
        long currentMinute = System.currentTimeMillis() / 60000L;
        boolean shouldPersistThisMinute = currentMinute != lastPersistMinute;
        if (shouldPersistThisMinute) {
            // 保存水质数据到数据库
            if (waterQualityData != null && !"N/A".equals(waterQualityData.getPhValue()) &&
                    !"N/A".equals(waterQualityData.getTemperature()) && !"N/A".equals(waterQualityData.getTurbidity())) {
                waterQualityDataService.save(waterQualityData);
            }
            // 保存到Redis（若温度发生波动则记录一次）
            waterSave(waterQualityData);
            lastPersistMinute = currentMinute;
        }

        // 广播给 WebSocket 订阅者（如果在运行）
        try {
            double ph = safeParseDouble(waterQualityData.getPhValue());
            double temp = safeParseDouble(waterQualityData.getTemperature());
            double turb = safeParseDouble(waterQualityData.getTurbidity());

            // 如果数据无效，使用默认值保持时间连续性
            if (ph == 0.0 && temp == 0.0 && turb == 0.0) {
                ph = 7.3;  // 默认pH值
                temp = 26.0; // 默认温度
                turb = 0.0;  // 默认浊度
                System.out.println("⚠️ 使用默认数据保持时间连续性");
            }

            long endTime = System.currentTimeMillis();
            System.out.println("📡 发送WebSocket数据: PH=" + ph + ", 温度=" + temp + ", 浊度=" + turb + ", 执行耗时: " + (endTime - startTime) + "ms");
            WaterQualityWebSocket.broadcast(ph, temp, turb);
        } catch (Exception ignored) {
        }
    }

    /**
     * @title: today
     * @desc:  查询当天Redis中的监测记录，供前端联动展示
     * @return: ResultVo
     */
    @GetMapping("today")
    public ResultVo today() {
        Date date = new Date();
        SimpleDateFormat day = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat hm = new SimpleDateFormat("HH:mm");
        String key = "water" + day.format(date);

        List<Object> raw = redisClient.lrange(key, 0, -1);
        List<Object> resp = new ArrayList<>();
        if (raw != null) {
            for (Object o : raw) {
                if (o instanceof WaterQualityData) {
                    WaterQualityData d = (WaterQualityData) o;
                    HashMap<String, Object> row = new HashMap<>();
                    Date ct = d.getCollectTime();
                    row.put("time", ct == null ? "" : hm.format(ct));
                    row.put("pH", d.getPhValue());
                    row.put("temperature", d.getTemperature());
                    row.put("turbidity", d.getTurbidity());
                    resp.add(row);
                }
            }
        }
        return ResultVo.success(resp);
    }

    /**
     * @title: range
     * @desc:  按最近 hours 小时过滤当天Redis记录（1/6/24），供趋势图调用
     * @param hours 最近小时数，允许 1、6、24，默认 1
     */
    @GetMapping("range")
    public ResultVo range(Integer hours) {
        int window = (hours == null ? 1 : hours);
        if (window != 1 && window != 6 && window != 24) {
            window = 1;
        }

        Date now = new Date();
        long threshold = now.getTime() - TimeUnit.HOURS.toMillis(window);

        SimpleDateFormat day = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat hm = new SimpleDateFormat("HH:mm");
        String key = "water" + day.format(now);

        List<Object> raw = redisClient.lrange(key, 0, -1);
        List<Object> resp = new ArrayList<>();
        if (raw != null) {
            for (Object o : raw) {
                if (o instanceof WaterQualityData) {
                    WaterQualityData d = (WaterQualityData) o;
                    Date ct = d.getCollectTime();
                    if (ct == null) {
                        continue;
                    }
                    if (ct.getTime() >= threshold && ct.getTime() <= now.getTime()) {
                        HashMap<String, Object> row = new HashMap<>();
                        row.put("time", hm.format(ct));
                        row.put("pH", d.getPhValue());
                        row.put("temperature", d.getTemperature());
                        row.put("turbidity", d.getTurbidity());
                        resp.add(row);
                    }
                }
            }
        }
        return ResultVo.success(resp);
    }

    private double safeParseDouble(String s) {
        if (s == null || s.trim().isEmpty() || "N/A".equalsIgnoreCase(s.trim())) {
            return 0.0;
        }
        return Double.parseDouble(s);
    }

    /**
     * @title: warning
     * @desc: 定义警告标准 - pH值在6.5-8.5之间，温度在20-30℃之间，浊度<3000 NTU
     * @params (WaterQualityData waterQualityData)
     * @return: void
     * @author: 杨旭朋
     * @date: 2025/9/23 10:25
     */
    public void warning(WaterQualityData waterQualityData) {
        if (waterQualityData == null) {
            return;
        }
        // 解析数值
        Double ph = parseNullableDouble(waterQualityData.getPhValue());
        Double temp = parseNullableDouble(waterQualityData.getTemperature());
        Double turb = parseNullableDouble(waterQualityData.getTurbidity());

        String deviceId = waterQualityData.getDeviceId();
        Long dataId = waterQualityData.getDataId();
        Date now = new Date();

        // 阈值范围
        double phMin = 6.5;
        double phMax = 8.5;
        double tempMin = 20.0;
        double tempMax = 30.0;
        double turbMax = 3000.0;

        // pH 异常：不在 [6.5, 8.5]
        if (ph != null && (ph < phMin || ph > phMax)) {
            handleAnomaly("PH", ph, String.format("%.1f-%.1f", phMin, phMax), deviceId, dataId, now, false);
        }
        // 温度 异常：不在 [20, 30]
        if (temp != null && (temp < tempMin || temp > tempMax)) {
            handleAnomaly("TEMP", temp, String.format("%.0f-%.0f℃", tempMin, tempMax), deviceId, dataId, now, true);
        }
        // 浊度 异常：>= 3000
        if (turb != null && turb >= turbMax) {
            handleAnomaly("TURBIDITY", turb, "<3000 NTU", deviceId, dataId, now, false);
        }
    }

    private Double parseNullableDouble(String value) {
        if (value == null) return null;
        String v = value.trim();
        if (v.isEmpty() || "N/A".equalsIgnoreCase(v)) return null;
        try {
            return Double.parseDouble(v);
        } catch (Exception e) {
            return null;
        }
    }


    private void handleAnomaly(String indicatorCode,
                               Double currentValue,
                               String normalRange,
                               String deviceId,
                               Long dataId,
                               Date now,
                               boolean isTemperature) {
        // 3分钟内同类型告警去重
        LambdaQueryWrapper<WaterQualityAnomaly> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WaterQualityAnomaly::getIndicatorCode, indicatorCode)
                .eq(WaterQualityAnomaly::getDeviceId, deviceId)
                .orderByDesc(WaterQualityAnomaly::getCreateTime)
                .last("limit 1");
        WaterQualityAnomaly recent = waterQualityAnomalyService.getOne(wrapper, false);

        boolean withinThreeMinutes = false;
        if (recent != null && recent.getCreateTime() != null) {
            long diffMs = now.getTime() - recent.getCreateTime().getTime();
            withinThreeMinutes = diffMs >= 0 && diffMs <= 3L * 60L * 1000L;
        }

        if (withinThreeMinutes) {
            // 温度在3分钟内变化 ±3 则更新原告警
            if (isTemperature && recent.getCurrentValue() != null) {
                double last = recent.getCurrentValue().doubleValue();
                if (Math.abs(currentValue - last) >= 3.0) {
                    recent.setCurrentValue(BigDecimal.valueOf(currentValue));
                    recent.setNormalRange(normalRange);
                    recent.setDataId(dataId != null ? dataId : 0L);
                    recent.setCreateTime(now);
                    waterQualityAnomalyService.updateById(recent);

                    // 推送告警更新到WebSocket
                    try {
                        com.zhentao.device.websocket.AlertWebSocketHandler.broadcastAlertUpdate(
                            recent.getAnomalyId(),
                            recent.getHandleStatus(),
                            "system"
                        );
                        System.out.println("📡 温度告警更新已推送到WebSocket客户端");
                    } catch (Exception e) {
                        System.err.println("❌ 推送温度告警更新失败: " + e.getMessage());
                    }
                }
            }
            // 非温度或温度变化 <3 时，不再创建新的告警
            return;
        }

        // 超过3分钟或无历史记录，则创建新的告警
        // 使用generateAlert方法，会自动触发WebSocket推送
        // 如果dataId为null，使用0L作为默认值
        Long finalDataId = dataId != null ? dataId : 0L;
        waterQualityAnomalyService.generateAlert(
            indicatorCode,
            currentValue,
            normalRange,
            deviceId,
            "设备" + deviceId,
            finalDataId
        );
    }
    /**
     * @title: waterSave
     * @desc:  存储方法
     * @params ()
     * @return: Result
     * @author: 杨旭朋
     * @date: 2025/9/23 19:14
     */
    public void waterSave(WaterQualityData waterQualityData) {
        if (waterQualityData == null) {
            return;
        }
        // 当前温度无效则不处理
        Double currentTemp = parseNullableDouble(waterQualityData.getTemperature());
        if (currentTemp == null) {
            return;
        }

        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(date);
        String key = "water" + dateStr;

        // 仅允许每分钟一条：若同一分钟已有一条，则覆盖；否则追加
        List<Object> lastList = redisClient.lrange(key, -1, -1);
        if (lastList == null || lastList.isEmpty()) {
            redisClient.rpush(key, waterQualityData);
            return;
        }

        Object lastObj = lastList.get(0);
        if (lastObj instanceof WaterQualityData) {
            WaterQualityData lastData = (WaterQualityData) lastObj;
            // 判断是否同一分钟
            Date lastCt = lastData.getCollectTime();
            Date curCt = waterQualityData.getCollectTime();
            long lastMin = lastCt == null ? -1L : (lastCt.getTime() / 60000L);
            long curMin = curCt == null ? (System.currentTimeMillis() / 60000L) : (curCt.getTime() / 60000L);
            if (lastMin == curMin) {
                // 同一分钟：覆盖最后一条，保证同一分钟最多一条
                try {
                    Long len = redisClient.llen(key);
                    if (len != null && len > 0) {
                        boolean success = redisClient.lset(key, len - 1, waterQualityData);
                        if (!success) {
                            System.err.println("⚠️ Redis lset操作失败，尝试rpush");
                            redisClient.rpush(key, waterQualityData);
                        }
                    } else {
                        redisClient.rpush(key, waterQualityData);
                    }
                } catch (Exception e) {
                    System.err.println("❌ Redis操作异常，使用rpush作为备选方案: " + e.getMessage());
                    redisClient.rpush(key, waterQualityData);
                }
        } else {
            // 新一分钟：直接追加一条
            boolean redisSuccess = redisClient.rpush(key, waterQualityData);
            if (!redisSuccess) {
                System.err.println("⚠️ Redis存储失败，数据可能丢失，但告警功能不受影响");
            }
        }
            return;
        }

        // 类型不匹配容错：直接追加
        boolean redisSuccess = redisClient.rpush(key, waterQualityData);
        if (!redisSuccess) {
            System.err.println("⚠️ Redis存储失败，数据可能丢失，但告警功能不受影响");
        }
    }

}
